package assist.client.gwt.service;

import java.util.ArrayList;
import java.util.Set;
import assist.domain.model.Game;
import assist.domain.model.Games;
import assist.domain.model.GamesQuery;
import assist.service.gwt.interfaces.HockeyStatsService;
import assist.service.gwt.interfaces.HockeyStatsServiceAsync;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.HasHandlers;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.HasData;
import com.google.web.bindery.event.shared.EventBus;

public class GamesProvider extends AsyncDataProvider<Game> 
    implements HasHandlers
{
    private final HockeyStatsServiceAsync hockeyStatsService =
        GWT.create(HockeyStatsService.class);      
    private GamesQuery gamesQuery;
    private Games games;
    private EventBus eventBus; 
    private HandlerManager handlerManager;
    
    
    public GamesProvider(EventBus eventBus)
    {
        this.eventBus = eventBus;     
        this.handlerManager = new HandlerManager(this);
    }
    
    public static class GamesChangeEvent extends ValueChangeEvent<Games>
    {
        protected GamesChangeEvent(Games games)
        {
            super(games);
        }      
    }  
    
    
    
    private void fireGamesChangeEvent()
    {
        this.fireEvent(new GamesChangeEvent(this.games));
    }     
    
    @Override
    public void fireEvent(GwtEvent<?> event)
    {       
        this.eventBus.fireEvent(event);
        this.handlerManager.fireEvent(event);
    }    

    @Override
    protected void onRangeChanged(HasData<Game> display)
    {
        //Invokes the loading message if games not loaded yet on first load.
        if (this.games == null)
        {
            display.setRowData(0, new ArrayList<Game>());
        }
        else
        {
System.err.println("TODO: Update display here"); //Should be done
            //NOTE: This is only needed if there is data out of range that needs
            //to be gotten asynchronously.
        }
    }
    
    
    private void fetchGamesAsync()
    {        
        hockeyStatsService.getGames(gamesQuery.getTeam(),  gamesQuery.getStart(), gamesQuery.getEnd(), 
                new AsyncCallback<Set<Game>>() {
            public void onFailure(Throwable caught) {
                Window.alert("Remote Procedure Call - Failure" + caught.getMessage());
            }

            public void onSuccess(Set<Game> gamesSet) {
                Games games = new Games();
                games.setGamesList(gamesSet);
                GamesProvider.this.games = games;
                
                GamesProvider.this.updateRowData(0, new ArrayList<Game>(games.getGamesList()));
                GamesProvider.this.updateRowCount(games.getGamesList().size(), true);
                fireGamesChangeEvent();
            }
        });         
    }
    
    /**
     * @param gamesQuery the gamesQuery to set
     */
    public void setGamesQuery(GamesQuery gamesQuery)
    {        
        this.fireEvent(new GamesChangeEvent(new Games()));
        this.gamesQuery = gamesQuery;
        this.fetchGamesAsync();
    }
      
    
    public void setGames(Games games)
    {
        this.games = games;
    }
    
    public Games getGames()
    {       
        return this.games;
    }
    
    /**
     * @return the gamesQuery
     */
    public GamesQuery getGamesQuery()
    {       
        return gamesQuery;
    }

    public HandlerRegistration addGamesChangeHandler(ValueChangeHandler<Games> handler)
    {
        // TODO Auto-generated method stub
        return this.handlerManager.addHandler(GamesChangeEvent.getType(), handler);
    }

}
